<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/4/23
 * Time: 13:43
 */

/**
 * 1.获取openID
 *  获取code
 *  根据code换取openID
 *
 * 2、验证jssdk（第一次签名）
 *  获取access_token
 *  获取ticket
 *  签名
 *  返回参数
 *
 *3、获取预处理prepay_id（第二次签名）
 *  获取openID
 *  notify_url
 *  签名
 *  获取prepay_id
 *
 * 3、返回微信支付参数（第三次签名）
 *  获取prepay_id
 *  签名
 * 返回参数
 */
namespace RjgcPay\WxWeChatPay;
class WePay{
    const APPID = 'wxccce3033a624d942';
    const MCHID = '1487319022';
    const KEY = 'e1dc18a17d3f59f74e5c6a0fea85bfed';
    const APPSECRET = 'e7e6e995e49c9a9c3f050d368189287d';

    const oauth_code='http://tx.life365.top/get-weixin-code.html?';
    //https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
    const oauth_access_token='https://api.weixin.qq.com/sns/oauth2/access_token';

    //https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
    const oauth_userinfo='https://api.weixin.qq.com/sns/userinfo';

    const pay_unifiedorder='https://api.mch.weixin.qq.com/pay/unifiedorder';

    /**
     * 获取jssdk信息
     * @return array
     * @throws \Exception
     */
    public function getJssdkInfo(){

        //1.获取jsapi_token票据
        $jsApiToken=$this->getJsApiTicket();

        $appId=self::APPID; //公众号标识
        $timestamp=time(); //生成签名的时间戳
        $nonceStr=$this->getRandCode(); //生成签名的随机字符串

        //$url='http://webapp.lz4746.com/jssdk.php';
        $url='http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];


        $signature=$this->jsSdkSignature($jsApiToken,$nonceStr,$timestamp,$url); //签名

       /* $dd=[
            'jsapi_ticket'=>$jsApiToken,
            'noncestr'=>$nonceStr,
            'timestamp'=>$timestamp,
            'url'=>$url,
            'signature'=>$signature,
        ];
        print_r($dd);die;*/

        return $data=[
            'appId'=>$appId,
            'timestamp'=>$timestamp,
            'nonceStr'=>$nonceStr,
            'signature'=>$signature
        ];
    }

    /*
     * 获取jssdk签名
     */
    public function jsSdkSignature($jsApiToken,$nonceStr,$timestamp,$url){
        $string1 = "jsapi_ticket=".$jsApiToken."&noncestr=".$nonceStr."&timestamp=".$timestamp."&url=".$url;
        $signature= sha1($string1);;// 必填，签名
        return $signature;// 必填，签名
    }

    /**
     * 获取随机码
     */
    public function getRandCode($num=16){
        $array=array(
            'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','U','W','X','Y','Z',
            'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','u','w','x','y','z',
            '1','2','3','4','5','6','7','8','9','0'
        );

        $temstr='';
        $max=count($array);
        for ($i=1;$i<=$num;$i++){
            $key=rand(0,$max-1);
            $temstr.=$array[$key];
        }
        return $temstr;
    }


    /**
     * 获取jssdk的Ticket
     * @return mixed
     * @throws \Exception
     */
    public function getJsApiTicket(){

        if (!empty($_COOKIE['jssdk_ticket'])){
            return $_COOKIE['jssdk_ticket'];
        }
        else{
            //https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
            //const jssdk_getticket='https://api.weixin.qq.com/cgi-bin/ticket/getticket';
            $url='https://api.weixin.qq.com/cgi-bin/ticket/getticket';
            $param=[
                'access_token'=>$this->curlGetAccessToken(),
                'type'=>'jsapi',
            ];

            $res=$this->http($url,$param,'','GET');
            $getticket=json_decode($res,true);

            setcookie('jssdk_ticket',$getticket['ticket'],time()+7000);

            return $getticket['ticket'];
        }

    }


    /**
     * 获取基础access_token
     * @return mixed
     * @throws \Exception
     */
    public function curlGetAccessToken(){

        if (!empty($_COOKIE['base_access_token'])){
            return $_COOKIE['base_access_token'];
        }

        //https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
       // const access_token='https://api.weixin.qq.com/cgi-bin';
        $url='https://api.weixin.qq.com/cgi-bin/token';
        $param=array(
            'grant_type'=>'client_credential',
            'appid'=>self::APPID,
            'secret'=>self::APPSECRET,
        );

        $res=$this->http($url,$param,'','GET');
        $access_token=json_decode($res,true);
        if (!empty($access_token)){
            /*$oauth_access_token=[
                'access_token'=>$access_token['access_token'],
                'get_time'=>time()
            ];
            $_SESSION['base_access_token']=$oauth_access_token;*/

            setcookie('base_access_token',$access_token['access_token'],time()+7000);
            return $access_token['access_token'];
        }
        else{
            throw new \Exception('AccessToken获取失败');
        }
    }


    public function getWxPayData($order_data=[],$openId){
        $pay_data=[];
        $pay_data['appid']=self::APPID; //公众账号ID 必填
        $pay_data['mch_id']=self::MCHID; //商户号 必填
        //$pay_data['sub_appid']='';  //子商户公众账号ID
        //$pay_data['sub_mch_id']=''; //子商户号

        //$pay_data['device_info']='';  //设备号 非必须
        $pay_data['nonce_str']=$this->getRandCode(32); //  随机字符串 必填


        //$pay_data['body']=urldecode($order_data['body']);//商品描述  必填
        $pay_data['body']=$order_data['body'];//商品描述  必填

        //$pay_data['detail']=$order_data['detail'];//商品详情  非必须
        //$pay_data['attach']=$order_data['attach'];//附加数据  非必须
        $pay_data['out_trade_no']=$order_data['out_trade_no'];//商户订单号  必填
        //$pay_data['fee_type']='CNY';//货币类型  非必须
        $pay_data['total_fee']=$order_data['total_fee']*100;//总金额  必填
        //$pay_data['product_id']=$order_data['product_id'];//商品ID  非必须



        $pay_data['spbill_create_ip']=$_SERVER['REMOTE_ADDR'];//终端IP  必填
        $pay_data['time_start']=date('YmdHis');//交易起始时间  必填
        //$pay_data['time_expire']=date('YmdHis');//交易结束时间  非必须
        //$pay_data['goods_tag']='WXG';//订单优惠标记  非必须

        //$pay_data['notify_url']=urldecode('http://webapp.lz4746.com/wxwechat/notify.php');//通知地址  必填
        $pay_data['notify_url']='http://webapp.lz4746.com/wxwechat/notify.php';//通知地址  必填

        $pay_data['trade_type']='JSAPI';//交易类型  必填
        //$pay_data['limit_pay']='no_credit';//指定支付方式  非必须

        $pay_data['openid']=$openId;//用户标识  必填
       // $pay_data['openid']='dddd';//用户标识  必填

        //$pay_data['sub_openid']='';//用户子标识  非必须

        //$pay_data['scene_info']='';//场景信息  非必须
        //$pay_data['sign_type']='MD5'; //签名类型 非必须 默认MD5
        //

        ksort($pay_data);
        //$pay_data['key'] = self::KEY;
        //$stringA=http_build_query($pay_data);
        //print_r($pay_data);


        $stringA='';
        foreach ($pay_data as $k=>$v){
            $stringA.= $k.'='.$v.'&';
        }
        $stringA.='key='.self::KEY;

        //print_r($stringA);
        //echo '===================';


        $string=strtoupper(md5($stringA));
        //print_r($string);


        unset($pay_data['key']);
        $pay_data['sign']=$string;//签名  必填

        $xml_dat="";
        $xml_dat.="<xml>".PHP_EOL;
        foreach ($pay_data as $k=>$v){


            //$xml_dat.="<$k>$v</$k>".PHP_EOL;

            //$xml_dat.="<".$k."><![CDATA[".$v."]]></".$k.">".PHP_EOL;

            /*if ($k==''){
                $xml_dat.="<".$k."><![CDATA[".$v."]]></".$k.">".PHP_EOL;
            }
            else{
                $xml_dat.="<sign>$v</sign>".PHP_EOL;
            }*/


           if ($k==''){
                $xml_dat.="<sign>$v</sign>".PHP_EOL;
            }
            else{
                $xml_dat.="<".$k."><![CDATA[".$v."]]></".$k.">".PHP_EOL;
            }

        }
        $xml_dat.="</xml>";

        //$xmlTpl=$this->dotoXml($pay_data);

/*       $xml2='<xml>
	            <appid><![CDATA[wxccce3033a624d942]]></appid>
	            <body><![CDATA[小张南山店-超市]]></body>
	            <mch_id><![CDATA[1487319022]]></mch_id>
	            <nonce_str><![CDATA[41uI9ETYSMAq4RFHS1oPs6qJjCFQeCqp]]></nonce_str>
	            <notify_url><![CDATA[http://webapp.lz4746.com/wxwechat/notify.php]]></notify_url>
	            <openid><![CDATA[oEKSg1Q5a4O_JJ4UeN57y_Mj76eE]]></openid>
	            <out_trade_no><![CDATA[20180424033622]]></out_trade_no>
	            <spbill_create_ip><![CDATA[127.0.0.1]]></spbill_create_ip>
	            <time_start><![CDATA[20180424033622]]></time_start>
	            <total_fee><![CDATA[10000]]></total_fee>
	            <trade_type><![CDATA[JSAPI]]></trade_type>
	            <sign>8F5007DE62E7F234168794946AB58767</sign>
            </xml>';*/



        //print_r($xml_dat);


        //$return_data=$this->http(self::pay_unifiedorder,'',$xml_dat,'POST'); //执行curl
        $return_data=$this->httpPost(self::pay_unifiedorder,$xml_dat); //执行curl

        //将返回的结果xml结果转成数组
        libxml_disable_entity_loader(true);
        $return_data_arr=simplexml_load_string($return_data,'SimpleXMLElement',LIBXML_NOCDATA);
        //print_r($return_data_arr);die;
       //


        //重新签名
        $sign_three['appId']=self::APPID;
        $sign_three['timeStamp']=time();
        $sign_three['nonceStr']=$this->getRandCode(32);
        $sign_three['package']='prepay_id='.$return_data_arr->prepay_id;
        $sign_three['signType']='MD5';
        ksort($sign_three);

        //print_r($sign_three);die;

        /*$stringThree='';
        foreach ($pay_data as $k=>$v){
            $stringThree.= $k.'='.$v.'&';
        }
        $stringThree.='key='.self::KEY;*/
        $appId=self::APPID;
        $timeStamp=time();
        $nonceStr=$this->getRandCode(32);
        $package='prepay_id='.$return_data_arr->prepay_id;
        $signType='MD5';
        $stringThree="appId=$appId&nonceStr=$nonceStr&package=$package&signType=$signType&timeStamp=$timeStamp";
        $stringThree=$stringThree.'&key='.self::KEY;

        /*print_r($stringThree);
        echo '------------';*/

       /* $sign_three['key'] = self::KEY;
        $stringThree=urldecode(http_build_query($sign_three));
        */
        $sign3=strtoupper(md5($stringThree));

        //print_r($sign3);die;

        /*$r_dataa=[
            'timeStamp'=>$sign_three['timeStamp'],
            'nonceStr'=>$sign_three['nonceStr'],
            'package'=>$return_data_arr['package'],
            'signType'=>$sign_three['signType'],
            'paySign'=>$sign3,
        ];*/

        $r_dataa=[
            'timeStamp'=>$timeStamp,
            'nonceStr'=>$nonceStr,
            'package'=>$package,
            'signType'=>$signType,
            'paySign'=>$sign3,
        ];

        //print_r($r_dataa);die;
        return $r_dataa;

    }

    private function dotoXml($data){
        $xml=new \SimpleXMLElement('<xml></xml>');
        foreach ($data as $key => $value) {
            $child = $xml->addChild($key);
            $node  = dom_import_simplexml($child);
            $cdata = $node->ownerDocument->createCDATASection($value);
            $node->appendChild($cdata);
        }
        return $xml->asXML();
    }


    /*
     * 获取openid
     */
    public function getOpenId(){
        $code=isset($_GET['code'])?$_GET['code']:'';

        if (!empty($_COOKIE['open_id'])){
            return $_COOKIE['open_id'];
        }
        else{
            if (empty($code)){
                $url=self::oauth_code;

                $redirect_uri='http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
                $param=array(
                    'appid'=>self::APPID,
                    'redirect_uri'=>$redirect_uri,
                    'response_type'=>'code',
                    'scope'=>'snsapi_base',
                    'state'=>'state'
                );

                $url=$url.http_build_query($param).'#wechat_redirect';
                header('location:'.$url);
            }
            else{
                $openid=$this->getAccessToken($code);
                return $openid;
            }
        }

    }


    /**
     * 获取access_token及openid
     * @param string $code
     * @return mixed
     * @throws \Exception
     */
    public function getAccessToken($code=''){

        $url=self::oauth_access_token;
        $param=array(
            'appid'=>self::APPID,
            'secret'=>self::APPSECRET,
            'code'=>$code,
            'grant_type'=>'authorization_code',
        );

        $res=$this->http($url,$param,'','GET');
        $access=json_decode($res,true);
        //print_r($access);die;
        if (!empty($access)){
            file_put_contents("test.txt",$access , FILE_APPEND);
            $openid=$access['openid'];
            //print_r($access);
            setcookie('open_id',$openid,time()+7000);
            //setcookie('access_token',$access['access_token'],time()+7000);
            //print_r($access['openid']);die;
            return $openid;
        }
        else{
            throw new \Exception('AccessToken获取失败');
        }

    }





    /**
     * curl请求
     *
     * @param $url 请求路径
     * @param string $param get请求参数
     * @param string $data post请求参数
     * @param string $method 请求方法
     * @return mixed
     */
    public  function http($url,$param='',$data='',$method="GET"){

        $opts=array(
            CURLOPT_TIMEOUT=>30,
            CURLOPT_RETURNTRANSFER=>1, //返回原输出
            CURLOPT_SSL_VERIFYHOST=>false,
            CURLOPT_SSL_VERIFYPEER=>false,//禁止对证书的验证
        );

        //拼接get请求数组组织新的URL地址
        if (empty($param)){
            $opts[CURLOPT_URL]=$url; //格式数组成get请求参数
        }
        else{
            $opts[CURLOPT_URL]=$url.'?'.http_build_query($param); //格式数组成get请求参数
        }


        //post请求参数
        if ($method=='POST'){

            $opts[CURLOPT_POST]=true;
            $opts[CURLOPT_POSTFIELDS]=$data;

            //如果post为字符串，那么就进行json提交
            /*if (is_string($data)){
                $opts[CURLOPT_HTTPHEADER]=array(
                    'Content-Type: application/json; charset=utf-8',
                    'Content-Length:' . strlen($data));
            }*/
        }

        $ch = curl_init();
        curl_setopt_array($ch, $opts);
        $res = curl_exec($ch);
        curl_close($ch);
        return $res;

    }

    public function httpPost($url,$post_data){
        /*$curl=curl_init();

        curl_setopt($curl,CURLOPT_HTTPHEADER,array('Content-Type:text/html;charset=utf-8'));
        curl_setopt($curl,CURLOPT_TIMEOUT,500);
        curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,false);
        curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);
        curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
        curl_setopt($curl,CURLOPT_PORT,true);
        curl_setopt($curl,CURLOPT_POSTFIELDS,$post_data);
        curl_setopt($curl,CURLOPT_FOLLOWLOCATION,true);
        curl_setopt($curl,CURLOPT_URL,$url);

        $res=curl_exec($curl);
        curl_close($curl);

        return $res;*/

        //初使化init方法
        $ch = curl_init();


        curl_setopt($ch, CURLOPT_URL, $url); //指定URL
        curl_setopt($ch, CURLOPT_POST, 1); //声明使用POST方式来进行发送
        curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type:text/xml; charset=utf-8"));

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //设定请求后返回结果 获取的信息以文件流的形式返回
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); //发送什么数据呢

        //忽略证书
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);


        curl_setopt($ch, CURLOPT_HEADER, 0); //忽略header头信息
        curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置超时时间

        $output = curl_exec($ch); //发送请求
        curl_close($ch); //关闭curl

        //返回数据
        return $output;
    }

    public function httpGet($url){
        $curl=curl_init();

        curl_setopt($curl,CURLOPT_HTTPHEADER,array('Content-Type:text/html;charset=utf-8'));
        curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
        curl_setopt($curl,CURLOPT_TIMEOUT,500);
        //为了
        //curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,true);
        //curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,true);

        curl_setopt($curl,CURLOPT_URL,$url);

        $res=curl_exec($curl);
        curl_close($curl);

        return $res;
    }

}